/*
 * Created on Jun 28, 2004
 *
 */
package littlecyberwar.tool;

import javax.swing.*;
import java.awt.*;
import java.awt.geom.*;
import java.awt.event.*;
import java.util.*;

import littlecyberwar.ui.*;
import littlecyberwar.model.*;

import littlecyberwar.util.*;

/**
 * @author Milton  Soong
 *
 * To change the template for this generated type comment go to
 * Window&gt;Preferences&gt;Java&gt;Code Generation&gt;Code and Comments
 */
public class MouseAlignVerticalHandler extends MultiSelectMouseHandler {
	
	public MouseAlignVerticalHandler() {
		super();
		id = H_ALIGNVERTICAL;
		unitSelectedText = "Click on a selected unit to have other selected units align vertically to it.";
		noUnitSelectedText = "Drag Select or shift-click select units you wish to align vertically.";
	}
	/**
	 * called here when a group of elements are selected
	 * The first element in the array contains the reference element
	 * 
	 * 1. Sort all the selected elements by vertical coordinates
	 * 2. Iterates from reference element all the way to the "top", and then calculate
	 * 		the new trandform for that unit
	 * 3. Iterates from reference element all the way "bottom", and then calculate new transform
	 * 4. redraw all the element area (old and new).
	 * 
	 */
	public void startAction( MouseEvent e ) {
		super.startAction(e);
	  	ArrayList sortList = createTopFrontList( selectedElements );
		TopGroupSortElementHolder refCont = (TopGroupSortElementHolder)sortList.get(0);		
	  	Collections.sort(sortList);
		
		// now find the index of the reference element in the new sorted list
		int refIndex = sortList.indexOf(refCont);
		if ( refIndex != -1 ){
			// Iterates from reference element all the way to the "front"
			AffineTransform trans = refCont.cont.element.getTransform();
			
			for ( int i=refIndex-1; i >= 0; i-- ){				 	
				TopGroupSortElementHolder sortHolder = (TopGroupSortElementHolder)sortList.get(i);
				Element el = sortHolder.cont.element;
				double currHeight = el.getHeight();
				trans = (AffineTransform)trans.clone();
				trans.translate(0, -currHeight);
				sortHolder.cont.currTrans = trans;
				Shape originalRec = sortHolder.cont.element.getRectangle();
				sortHolder.cont.selectedRectangle = trans.createTransformedShape(originalRec);
//				Area a = new Area(el.getFinalShape().getBounds());				
//				selectedArea.add(a);
				DirtyAreaManager.addDirtyArea(el.getFinalShape());
			}
			
			// Iterates from reference element all the way "bottom"
			trans = refCont.cont.element.getTransform();
			double lastHeight = refCont.cont.element.getHeight();
			int limit = sortList.size();
			
			for ( int i=refIndex+1; i < limit; i++ ){				 	
				TopGroupSortElementHolder sortHolder = (TopGroupSortElementHolder)sortList.get(i);
				Element el = sortHolder.cont.element;
				double currHeight = el.getHeight();;
				trans = (AffineTransform)trans.clone();
				trans.translate(0, lastHeight);
				sortHolder.cont.currTrans = trans;
				Shape originalRec = sortHolder.cont.element.getRectangle();
				sortHolder.cont.selectedRectangle = trans.createTransformedShape(originalRec);
				lastHeight = currHeight;
//				Area a = new Area(el.getFinalShape().getBounds());				
//				selectedArea.add(a);
				DirtyAreaManager.addDirtyArea(el.getFinalShape());
			}
//			Rectangle rec = selectedArea.getBounds();			
//			rec.grow(PlayingBoardPanel._DEFAULT_STROKE_WIDTH, PlayingBoardPanel._DEFAULT_STROKE_WIDTH);
//			comp.repaint(rec);
			
			DirtyAreaManager.checkAndRepaint(comp);
			// stopAction();
		}
		return;
	}

	/**
	 * @author Milton  Soong
	 *
	 * this class is use to hold the elements in the process of being sorted
	 * for sorting by the y coordinate
	 */
	public class TopGroupSortElementHolder implements Comparable {
		public SelectedElementContainer cont;
		public double refPointX, refPointY;
		
		public int compareTo(Object o) {
			int val = 0;
			TopGroupSortElementHolder target = (TopGroupSortElementHolder)o;
			if ( this.refPointY < target.refPointY ){
				val = -1;
			} else if ( this.refPointY > target.refPointY ){
				val = 1;
			}
			return ( val );
		}
	}

	public ArrayList createTopFrontList( ArrayList elementsIn ) {
		Element refEl = ((SelectedElementContainer)selectedElements.get(0)).element;
			
		AffineTransform refTrans = refEl.getTransform();
		ArrayList resultList = new ArrayList(elementsIn.size());
	
		/**
		 * Now loop through all the selected elements, and then inverse
		 * transform their left front point onto the reference coordinate
		 */
		for ( int i=0; i < selectedElements.size(); i++ ) {
			SelectedElementContainer cont = ((SelectedElementContainer)selectedElements.get(i));
			Element el = cont.element;			  	
			Point2D leftFrontP = el.getFinalLeftFrontPoint();
			Point2D lfpRefCoordinate = null;
			try {
				lfpRefCoordinate = refTrans.inverseTransform(leftFrontP, lfpRefCoordinate);
			} catch ( Exception ex ){
				ex.printStackTrace();
			}
			TopGroupSortElementHolder holder = new TopGroupSortElementHolder();
			holder.cont = cont;
			holder.refPointX = lfpRefCoordinate.getX();
			holder.refPointY = lfpRefCoordinate.getY();
				
			resultList.add(holder);
		}
		return( resultList );		
	}

	public UnitCommand stopAction() {
	  // .out("stopAction(): mouseReleased");
	  MultiUnitCommand multCmd = null;
	  if ( selectedElements.size() > 1){
		  multCmd = new MultiUnitCommand();  	
	  }
	  UnitCommand cmd=null;
	  for ( int i=0; i< selectedElements.size(); i++){
		  SelectedElementContainer elcont = (SelectedElementContainer)selectedElements.get(i);
		  Element el = elcont.element;
		
		  if ( elcont.selectedRectangle != null ) {
			  // .out("el.getElementId()= " + el.getElementId());
			  cmd = new UnitCommand(el.getElementId(), id, elcont.currTrans, pixMoved/mapScale);		
			  cmd.setPlayerName(Players.getSelfName());
			  if ( multCmd != null ){
				  multCmd.addUnitCommand(cmd);
			  }
		  } else {
			  Debug.out("( elcont.selectedRectangle == null )");
		  }
			  // clean up container
//		elcont.resetElementContainer();
	  }
	  if (multCmd != null ){
		  cmd = multCmd;
	  }
	  return ( cmd );      
	}

}
